#include <cjson/cJSON.h>
#include <sys/stat.h>
#include <time.h>
#include "com_list.h"
#include "sqldb.h"
#include "init.h"
#include <pthread.h>
#include<sys/socket.h>
#include<unistd.h>
#include<string.h>
#include<stdlib.h>
#include<sys/select.h>
#include<netinet/in.h>
#include<arpa/inet.h>

//需要创建的两个表
static unsigned char web_db_file_path[256];
static unsigned char web_db_table[256];
static sqlite3 *web_db_g; //全局使用的sqlite3的句柄
static const char config_file_path[] =  "/home/hongyu/web_data.json"; //初始化使用的配置文件;
//完善的增删改查功能

typedef void (*exec_script)(int, char **, char *); //参数个数,对参数进行解析,返回结果给Web 或者普通命令行惊醒使用;

typedef struct {
    char exec_func_name[256];
    exec_script opt_exec;
} script_exec_group;

typedef struct {
    int INT32;
    unsigned int UINT32;
    char INT8;
    unsigned int UINT8;
    char BIT: 1;
    short INT16;
    unsigned short UINT16;
    long long INT64;
    unsigned long long UINT64;
    char *STR; //存储字符串的类型
} para_type; //内存压缩使用

typedef enum {
    UPDATE_SQLITE, //UPDATE
    DEL_SQLITE_PARA, //DEAL
    NONE
} opt_type;

enum {
    ID = 0,
    NAME = 1,
    VALUE = 2,
    TYPE = 3,
    MODE = 4,
    ATTR = 5
};

typedef enum {
    RADIO_INFO = 0x1,
    FPGA_INFO = 0x2,
    DEVICE_INFO = 0x4,
    IP_INFO = 3,
    NET_CONFIG_INFO=5,
    NET_CONFIG_DEVICE=6,
    SUB_DEVICE=7,
    ADC_CONFIG_INFO=8,
    ALL_INFO = 0xFF
} select_sql_attr;

typedef void (*func_temp)(uint32_t, para_type, opt_type); //在默认的情况下通常挂载的类型为 RO 只读类型;对相应的数据类型操作
void type_check(char *name, char *data, para_type *type);

void hex_echo(uint8_t *msg, int len) {
    int i = 0, cnt = 0;

    for (i = 0; i < len; i++) {
        printf("%02x ", msg[i]);
        cnt++;
        if (cnt % 8 == 0) {
            printf("\n");
        }
    }
    printf("\n\n");
}

typedef struct {
    cJSON *db_file_name;
    cJSON *db_table_name;
    cJSON *index;
    cJSON *name;
    cJSON *value;
    cJSON *mode;
    cJSON *select;
    cJSON *type;
} record_json_t;

typedef struct list_st {
    uint32_t index; //索引最大值为20个字节 在程序中自己解决倍率的问题
    char name[256]; //参数名称最多维护为256个字节
    para_type type; // 使用的数据源类型
    char value[256];
    char value_type[10];
    char mode; //0 为只读类型 1为只写类型 2为可读可写
    unsigned char select; //从数据库选择相应的数据类型
    char use_st;
    func_temp common_func;
    COM_LIST_HEAD_t node;
} map_list;

LIST_HEAD(web_data_list); //Web 命令行中所示所使用的根节点

void web_list_push_node(map_list *new_node) { //在双向链表中填入相关的节点
    list_add_tail(&(new_node->node), &web_data_list);
}

int web_list_update_node(uint32_t index, char *value) { //根据index 值先找到相关的节点;只有在具体的应用中才能知道实际的类别
    // 内存中的数据为最新的数据
    // 在数据库中存储的数值均为char*
    COM_LIST_HEAD_t *cur;
    map_list *search;
    list_each(cur, &web_data_list) {
        search = list_node_get(cur, map_list, node); // 寻找节点
        if (search != NULL) {
            if (search->mode & 0x1) { // 说明数据库使用此参数
                if (search->index == index) {
                    if (strcmp(search->value, value)) {
                        memset(search->value, 0, 256); //search->value 为网页中原始传过来的数据
                        strcpy(search->value, value); //value值的更新;之前的空间;由于之前的限制所于一不会访问到不好的数据
                        type_check(search->value_type, search->value, &search->type); //正确的写入数据库,并对数据进行操作;
                        // 不会出现重复操作
                        search->common_func(index, search->type, UPDATE_SQLITE); //(先对比数据在决定是否继续更新sqlite);
                    } else {
                        printf("不做修改\n");
                    }
                    // 对数据库中的数据源更新
                    return 0;
                }
            }
        }
    }
    return 1; //操作失败
}

int web_list_del_node(uint32_t index) {
    COM_LIST_HEAD_t *cur;
    map_list *search;
    list_each(cur, &web_data_list) {
        search = list_node_get(cur, map_list, node);
        if (search != NULL) {
            if (search->index == index) {
                search->common_func(index, search->type, DEL_SQLITE_PARA); //从数据库中删除，从内存中删除
                return 0; //操作成功
            }
        }
    }
    return 1;
}

void type_check(char *name, char *data, para_type *type) { //整数操作,不涉及到float的类型,不考虑倍率的问题
    if (data != NULL) {//实际使用的是maplist 的value的数据结构
        type->STR = data; //首先先改变以下的原始指向 //
        if (!strcmp(name, "int8")) {
            type->INT8 = (int8_t) strtol(data, NULL, 10);
        } else if (!strcmp(name, "uint8")) {
            type->UINT8 = (uint8_t) strtol(data, NULL, 10);
        } else if (!strcmp(name, "uint16")) {
            type->UINT16 = (uint16_t) strtol(data, NULL, 10);
        } else if (!strcmp(name, "int16")) {
            type->INT16 = (int16_t) strtol(data, NULL, 10);
        } else if (!strcmp(name, "int32")) {
            type->INT32 = (int32_t) strtol(data, NULL, 10);
        } else if (!strcmp(name, "uint32")) {
            type->UINT32 = (uint32_t) strtol(data, NULL, 10);
        }
    }
}

void com_sql_opt(uint32_t index, para_type data, opt_type type) { //基本操作更新数据库,list+sqlite 实现的redis内存数据库//
    // 最后再决定
    COM_LIST_HEAD_t *cur;
    map_list *search;
    if (type != NONE) {
        list_each(cur, &web_data_list) {
            search = list_node_get(cur, map_list, node);
            if (search != NULL) {
                if (search->index == index) {
                    search->type = data; //更新节点的value值; 这是在内存中已经转化好可以使用的数据;开局只读一次数据库;其余对数据库
                    // 谨慎操作;从数据库中的读操作只发生在重启的时候
                    if (type == UPDATE_SQLITE) {
                        update_db(index, search->value, web_db_table, web_db_g);
                    } else if (type == DEL_SQLITE_PARA) { //对节点的通用操作
                        delete_db(index, web_db_table, web_db_g);
                        list_del(&search->node);
                        free(search);
                        search = NULL;
                    }
                }
            }
        }
    }
}

int web_get_info(select_sql_attr attr, char *res) {
    COM_LIST_HEAD_t *cur;
    map_list *search;
    int len = 0;

    list_each(cur, &web_data_list) {
        search = list_node_get(cur, map_list, node);
        if (search != NULL) {
            if (search->select == attr) { //根据属性查询回来相应的数值,并返回结果
                search->common_func(search->index, search->type, NONE); //先计算相应的结果;
                sprintf(res + len, "%s:%#x=%s&",search->name,search->index, search->value);
                len = (int) strlen(res);
            }
        }
    }
    return 0;
}

map_list *web_search_index(uint32_t index, para_type *value) { //改变获取的参数值
    COM_LIST_HEAD_t *cur;
    map_list *search;
    list_each(cur, &web_data_list) {
        search = list_node_get(cur, map_list, node);
        if (search != NULL && search->index == index) {
            if (value != NULL) {
                *value = search->type;
            }
            return search;
        }
    }
    return NULL;
}


int init_web_data(int *all_size, int *config_size_real) //TODO: 设备自用web调试使用,如果没有就进行插入操作;重新加载配置按钮进行使用
// ;添加去重复操作代码;redis的功能
{
    static unsigned char opt_flag = 0;
    cJSON *root, *config, *tmp, *web_db_path, *web_db_name;
    int i, config_size = 0;
    struct stat file_size;

    if (stat(config_file_path, &file_size) < 0) {
        printf("文件不存在就不再做任何的操作\n");
        return -1;
    }

    *all_size = (int) file_size.st_size; //转化为int类型
    char *buffer = (char *) calloc(file_size.st_size, sizeof(char));
    FILE *fp = fopen(config_file_path, "r"); //TODO:加上错误判断
    fread(buffer, file_size.st_size, 1, fp);
    root = cJSON_Parse(buffer);

    if (root == NULL) {
        printf("json config text is error,please check !!!");
        return -1;
    }

    config = cJSON_GetObjectItem(root, "config");
    record_json_t json_data;
    map_list *para_record;

    memset(web_db_file_path, 0, sizeof(web_db_file_path));
    memset(web_db_table, 0, sizeof(web_db_table));
    web_db_path = cJSON_GetObjectItem(root, "web_data_db");
    strncpy((char *) web_db_file_path, web_db_path->valuestring ? web_db_path->valuestring : "none", 256);
    //其实可以
    web_db_name = cJSON_GetObjectItem(root, "web_data_table");
    strncpy((char *) web_db_table, web_db_name->valuestring ? web_db_name->valuestring : "node", 256);
    //判断参数是否真的存在

    if (config != NULL) {
        config_size = cJSON_GetArraySize(config);
        printf("config size:%d\n", config_size);
        for (i = 0; i < config_size; i++) {
            tmp = cJSON_GetArrayItem(config, i);
            json_data.index = cJSON_GetObjectItem(tmp, "index");
            json_data.name = cJSON_GetObjectItem(tmp, "name");
            json_data.value = cJSON_GetObjectItem(tmp, "value");
            json_data.mode = cJSON_GetObjectItem(tmp, "mode");
            json_data.select = cJSON_GetObjectItem(tmp, "attr");
            json_data.type = cJSON_GetObjectItem(tmp, "type");
            para_record = (map_list *) malloc(sizeof(map_list));
            para_record->index = strtol(json_data.index->valuestring, NULL, 16);
            strncpy(para_record->value, json_data.value->valuestring, 256);
            strncpy(para_record->name, json_data.name->valuestring, 256);
            strncpy(para_record->value_type, json_data.type->valuestring, 10);
            para_record->mode = (json_data.mode->valueint & 0x3);
            para_record->select = json_data.select->valueint;
            para_record->use_st = 1; //说明此ID已经在初始化化的时候存在;
            para_record->common_func = com_sql_opt; //首先对数据绑定通用操作
            type_check(para_record->value_type, para_record->value, &para_record->type); //将正常的数据提取出来;在顶层中完成了
            // 完成参数的基本赋值进行使用
            web_list_push_node(para_record);
        }
    }

    free(buffer);
    buffer = NULL;
    cJSON_Delete(root);
    *config_size_real = config_size; //初始化得到的参数个数;
    return 0;
}

int index_sql = 0;
char ID_SQL[4096][6][256]; //记录4096对,键值对;相当于简易radis的功能;

static int web_db_change_check(void *data, int argc, char **argv, char **azColName) { //数据包会更新;
    COM_LIST_HEAD_t *cur;
    map_list *search;
    strncpy(ID_SQL[index_sql][0], argv[ID], sizeof(ID_SQL[0][0]));
    strncpy(ID_SQL[index_sql][1], argv[NAME], sizeof(ID_SQL[0][0]));
    strncpy(ID_SQL[index_sql][2], argv[VALUE], sizeof(ID_SQL[0][0]));
    strncpy(ID_SQL[index_sql][3], argv[TYPE], sizeof(ID_SQL[0][0]));
    strncpy(ID_SQL[index_sql][4], argv[MODE], sizeof(ID_SQL[0][0]));
    strncpy(ID_SQL[index_sql][5], argv[ATTR], sizeof(ID_SQL[0][0]));

    index_sql++;
    list_each(cur, &web_data_list) {
        search = list_node_get(cur, map_list, node);
        if (search != NULL) {
            if (search->index == strtol(argv[0], NULL, 16)) { //更新内存建表数据和数据库保持一样
                strncpy(search->value, argv[2], sizeof(search->value));
                type_check(search->value_type, search->value, &search->type); //更新一遍数据表建表当中的数据
            }
        }
    }
    return 0;
}

void check_db_change(const char *table, sqlite3 *db) //此函数通过ID值查寻自己需要的数据,每个🆔值绑定所有相应的数据,只能做不同的数据进行不同的初始化
{
    char cmd[256] = {0};
    int ret;
    char *errMsg;
    sprintf(cmd, "SELECT * FROM %s;", table);//select 选择条件,从不同的数据表筛选出来
    ret = sqlite3_exec(db, cmd, web_db_change_check, NULL, &errMsg); //data数据查询回来

    if (ret) {
        printf("querry all eror %s\n", errMsg);
        return;
    }
    int i;
    COM_LIST_HEAD_t *cur;
    map_list *search;
    char pool[4096];
    char sql[512];
    list_each(cur, &web_data_list) {
        search = list_node_get(cur, map_list, node);
        if (search != NULL) {
            for (i = 0; i < index_sql; i++) {
                if (search->index == strtol(ID_SQL[i][ID], NULL, 16)) { //检查修改的属性值是否已经修改;根据ID修改
                    //已经修改的值
//                        printf("%s %s %s %s %ld %ld\n",ID_SQL[i][ID],ID_SQL[i][NAME],ID_SQL[i][TYPE],
//                               ID_SQL[i][VALUE],strtol(ID_SQL[i][MODE],NULL,10),strtol(ID_SQL[i][ATTR],
//                                                                                       NULL,10));
                    if (search->mode != strtol(ID_SQL[i][MODE], NULL, 10)) {
                        sprintf(sql, "UPDATE web set MODE = %d where ID == \'%#x\';",
                                search->mode, search->index);
                        update_com(sql, web_db_g);
                        memset(sql, 0, 512);
                    }
                    if (search->select != strtol(ID_SQL[i][ATTR], NULL, 10)) {
                        sprintf(sql, "UPDATE web set ATTR = %d where ID == \'%#x\';",
                                search->select, search->index);
                        update_com(sql, web_db_g);
                        memset(sql, 0, 512);
                    }
                    if (strcmp(search->name, ID_SQL[i][NAME])) {
                        sprintf(sql, "UPDATE web set NAME = \'%s\' where ID == \'%#x\';",
                                search->name, search->index);
                        update_com(sql, web_db_g);
                        memset(sql, 0, 512);
                    }
                    if (strcmp(search->value_type, ID_SQL[i][TYPE])) {
                        sprintf(sql, "UPDATE web set TYPE = \'%s\' where ID == \'%#x\';",
                                search->value_type, search->index);
                        update_com(sql, web_db_g);
                        memset(sql, 0, 512);
                    }
                    break;
                }
            }
            if (i == index_sql) { //检查是否有新的元素插入进去
                sprintf(pool, "VALUES(\'%#x\',\'%s\',\'%s\',\'%s\',%d,%d)", search->index, search->name,
                        search->value, search->value_type, search->mode, search->select);
                insert_db(pool, web_db_table, web_db_g);
            }
        }
    }
}

void init_web_database(int all_data_size) { //如果数据库文件已存在就不在创建数据库文件,就直接操作数据库;
    //TODO: create table; 打开一个句柄;
    //TODO: 一次性插入所有数据;初始化的速度会更加快速;
    //TODO: 监测数据源表是否存在
    int ret = sqlite3_open(web_db_file_path, &web_db_g);
    if (ret != SQLITE_OK) {
        printf("can't create web db file\n");
    }
    char *errMsg;
    errMsg = create_db(
            " (ID STR PRIMARY KEY NOT NULL,NAME NOT NULL,VALUE NOT NULL,TYPE NOT NULL,MODE INT NOT NULL,"
            "ATTR INT NOT NULL);",
            web_db_table, web_db_g);

    char *buffer_loop = (char *) calloc(all_data_size, sizeof(char));
    if (buffer_loop == NULL) {
        printf("calloc error:%s\n", strerror(errno)); //系统分配出错;
        return;
    }
    char insert_flag = 0;
    char tmp[4092] = {0};
    if (strstr(errMsg, "OK")) { //创建表格成功
        COM_LIST_HEAD_t *cur;
        map_list *search;
        list_each(cur, &web_data_list) {
            search = list_node_get(cur, map_list, node);
            if (search != NULL) {
                if (insert_flag == 0) {
                    sprintf(buffer_loop,
                            "SELECT \'%#x\' AS ID,\'%s\' AS NAME,\'%s\' AS VALUE,\'%s\' AS TYPE,%d AS MODE,"
                            "%d AS ATTR",
                            search->index, search->name, search->value, search->value_type, search->mode,
                            search->select);
                } else {
                    memset(tmp, 0, sizeof(tmp));
                    sprintf(tmp, " UNION SELECT \'%#x\',\'%s\',\'%s\',\'%s\',\'%d\',\'%d\'",
                            search->index, search->name, search->value, search->value_type, search->mode,
                            search->select);
                    strcat(buffer_loop, tmp);
                }
                insert_flag = 1;
            }
        }
        insert_db(buffer_loop, web_db_table, web_db_g);
    } else if (strstr(errMsg, "exists")) { //表格重复创建,不会再重复创建新表进行使用;只是会告诉用户表已经存在
        check_db_change(web_db_table, web_db_g);
        printf("table is exists \n");
    }
}

void fpga(uint32_t index, para_type value, opt_type opt) { //this->para_type->STR > this->value(实际组包的sql 语句)
    printf("I am here ~^^~ %s \n", value.STR);
    memset(value.STR, 0, strlen(value.STR));
    strcpy(value.STR, "hello world");
    com_sql_opt(index, value, opt); //通用的数据库操作
}

void driver_debug(void) { //first use 经过测试可以使用;
    map_list *search = web_search_index(0x1, NULL); //假设操作的是FPGA 的参数ID为 0x1

    if (search != NULL) {
        search->common_func = fpga; //只进行相关的赋值操作,不在初始化的时候执行
    }
}

void server_debug(void) { //绑定脚本处理函数;
    printf("server debug\n");
}

void testv1(uint32_t index, para_type value, opt_type opt) {
    memset(value.STR, 0, 256);
    if (index == 0x2) {
        value.INT32 = 123;
        sprintf(value.STR, "%d", value.INT32); //可以使用的通用数据类型;
    } else if (index == 0x5) {
        value.INT8 = 110;
        sprintf(value.STR, "%d", value.INT8);
    }

    printf("search buffer %s\n", value.STR); //为一个野指针
    com_sql_opt(index, value, opt);
}

void user_clock(void) { //可以使用绑定同一个
    map_list *search = web_search_index(0x2, NULL);
    if (search != NULL) {
        search->common_func = testv1;
    }
}


void test(void) {
    map_list *search = web_search_index(0x5, NULL);
    if (search != NULL) {
        search->common_func = testv1;
    }
}

DRIVER_INIT(driver_debug);
DRIVER_INIT(test);
DRIVER_INIT(user_clock);
SERVER_INIT(server_debug);

void init_main(void) {
    driver_init *DRIVER_CALL_INIT = &driver_init_start; //驱动程序挂载
    server_init *SERVER_CALL_INIT = &server_init_start; //服务应用程序挂载
    __INIT_FUNC(DRIVER);
    __INIT_FUNC(SERVER);
}

void FPGA_DEAL(int argc, char **argv, char *res) {
    int i;
    char temp[1024][256]; //FIXME:“指针的指向的参数是一个初始地址,需要将空间内的值,copy过来才可以使用;这一步不能少”
    if (argv != NULL) {
        memcpy(temp, argv, 256 * 1024);
    }

    if (res != NULL) {
        sprintf(res, "FPGA CMD EXEC: GOOD\n"); //如果RES被使用就是上报给网页和命令行的最终结果;
    }
}

void CLOCK_DEAL(int argc, char **argv, char *res) { //测试成功;使用没有任何问题
    char temp[1024][256]; //FIXME:“指针的指向的参数是一个地址,需要将空间内的值,copy过来才可以使用;这一步不能少”
    if (argv != NULL) {
        memcpy(temp, argv, 256 * 1024);
    }

    const char useage[] = "help:\n"
                          "st #check clock pll locked status\n"
                          "[addr] [value] #写入相关的寄存器的地址和值\n";
    if(argc != 2){
        sprintf(res, useage);
    }else{
        sprintf(res,"cli I am very good\n");
    }
}

void complete_func(int,char**,char*);

static const script_exec_group create_exec_array[] = { //网页命令行的处理方式,命令注册执行的方式;
        {"FPGA",FPGA_DEAL},
        {"CLOCK",CLOCK_DEAL},
        {"COMPLETE",complete_func}
};

static const int exec_cmd_cnt = sizeof(create_exec_array) / sizeof(create_exec_array[0]);

void complete_func(int argc,char **argv,char *res){
    int i;
    int len =0;
    for ( i = 0 ; i < exec_cmd_cnt ; i++){
        if(!strcmp(create_exec_array[i].exec_func_name,"COMPLETE")){
            continue;
        }
        sprintf(res+len,"%s ",create_exec_array[i].exec_func_name);
        len = (int)strlen(res); //通过len计算好返回的填入的地址空间;
    }
}
void find_script_exec(int argc, char **argv, char *res) { //strcat 拼接字符串,检出BUFFER剩余空间;一条命令,一条命令的执行;
    int i;
    char temp[1024][256];

    if (argv != NULL) { //查看是否为空;传进来的实参空间大小固定为 1024*56
        memcpy(temp, argv, 1024 * 256);
    }

    for (i = 0; i < exec_cmd_cnt; i++) {
        if (!strcmp(create_exec_array[i].exec_func_name, temp[0])) {
            printf("I am here\n");
            create_exec_array[i].opt_exec(argc, (char **) temp, res);
        }
    }
}

void deal_script(char *buffer, char *send_buffer_packet) { //限制的字节数为4千个字节;网页命令行的使用方法;同时也是新版fun命令的方法
    char *ptr;
    char *tmp;
    char argv[1024][256];
    int argc;
    int len;

//    printf("buffer: %s\n", buffer);
    while ((ptr = strsep(&buffer, ";")) != NULL) { //";" 为分隔符 一个命令
        if (!strcmp(ptr, "")) break; //多一个空字符的情况;特殊情况;必须将空字符去除才可以使用;一般是发生在分隔符的后边;
        argc = 0;
        while ((tmp = strsep(&ptr, " ")) != NULL) { // " " 命令接卸的分隔符
//            printf("deal %s\n", tmp);
            strncpy(argv[argc], tmp, 256);
            argc++;
        }
        len = (int) strlen(send_buffer_packet);
        find_script_exec(argc, (char **) argv, send_buffer_packet + len); //往不同的地址下进行数据的复制;
        // 完成相关的组包,然后在发送;
        memset(argv, 0, 256 * argc); //清空再次传进去的参数;
    }
}

void web_com_write_deal(char *pool, char *res) {
    char *ptr;
    char *tmp;
    char first[256], second[256];
    char *tmp_update[] = {first, second}; //一个键值对的使用
    int i;

//    printf("buffer: %s\n", pool);
    while ((ptr = strsep(&pool, "&")) != NULL) { //";" 为分隔符 一个命令
        if (!strcmp(ptr, "")) break; //多一个空字符的情况;特殊情况;必须将空字符去除才可以使用;一般是发生在分隔符的后边;
        i = 0;
        while ((tmp = strsep(&ptr, "=")) != NULL) { // " " 命令接卸的分隔符
            if (i == 2 && strlen(tmp) > 256) break; //异常判断不进行处理;
            strcpy(tmp_update[i++], tmp);
        }
//        printf("ID %s value ：%s\n", tmp_update[0], tmp_update[1]);
        web_list_update_node(strtol(tmp_update[0], NULL, 16), tmp_update[1]);
        strcpy(res, "update rams pars and sqlite3 successed");
        memset(first, 0, 256);
        memset(second, 0, 256);
        // 完成相关的组包,然后在发送;
    }
}

void web_com_del_deal(char *pool, char *res) {
    char *ptr;
    while ((ptr = strsep(&pool, "&")) != NULL) { //";" 为分隔符 一个命令
        if (!strcmp(ptr, "")) break; //多一个空字符的情况;特殊情况;必须将空字符去除才可以使用;一般是发生在分隔符的后边;
        web_list_del_node(strtol(ptr, NULL, 16));
        // 完成相关的组包,然后在发送;
    }
}

void login_web_check(char *pool,char *res){
    char *ptr;
    char *tmp;
    int flag=0;
    char tmp_pre[256]={0};
    while((ptr = strsep(&pool,"&")) != NULL){
        if(!strcmp(ptr,"")) break;
        while((tmp=strsep(&ptr,"=")) != NULL){
            if(!strcmp(tmp,"")) break;
            if(strstr(tmp_pre,"admin") && !strcmp(ptr,"yd600105")){
                sprintf(res,"admin login");
                flag = 1;
                return;
            }else if(strstr(tmp_pre,"factory") && !strcmp(ptr,"2021-08-23")){
                sprintf(res,"factory login");
                flag = 1;
                return;
            }
            strncpy(tmp_pre,tmp,256);
        }
    }
    if(flag == 0){
        sprintf(res,"none");
    }
}

void check_and_deal_and_parse(char *pool, char *res) { //Web 上的增删改查的要求都没有问题
    char *ptr;
    if (strstr(pool, "&")) {
        sprintf(res, "cmd error please check");
    }
    ptr = strsep(&pool, "&");
    if (!strcmp(ptr, "cmd=com_write")) { //通用数据库设置
        sprintf(res, "%s&", ptr);
        web_com_write_deal(pool, res + strlen(res));
    } else if (!strcmp(ptr, "cmd=script")) { //对脚本进行一次性解析
        sprintf(res, "%s&", ptr);
        deal_script(pool, res); //已经在函数内部实现了头部判断
    } else if (!strcmp(ptr, "cmd=device_info")) {
        sprintf(res, "%s&", ptr);
        web_get_info(DEVICE_INFO, res + strlen(res));
    } else if (!strcmp(ptr, "cmd=fpga_info")) {
        sprintf(res, "%s&", ptr);
        web_get_info(FPGA_INFO, res + strlen(res));
    } else if (!strcmp(ptr, "cmd=com_del")) {
        sprintf(res, "%s&", ptr);
        web_com_del_deal(pool, res + strlen(res)); //删除数据库中的内容;
//        COM_LIST_HEAD_t *cur; //验证RAMS中的键值对是否没有删除成功
//        map_list *search;
//        list_each(cur, &web_data_list) {
//            search = list_node_get(cur, map_list, node);
//            if (search != NULL) {
//                printf("del after index: %#x\n", search->index);
//            }
//        }
    } else if (!strcmp(ptr, "cmd=radio_info")) { //先删除节点在
        sprintf(res, "%s&", ptr);
        web_get_info(RADIO_INFO, res + strlen(res));
    }else if(!strcmp(ptr,"cmd=login")){
        sprintf(res,"%s&",ptr);
        login_web_check(pool,res+strlen(res));
    }else if(!strcmp(ptr,"cmd=ip_info")){
        sprintf(res,"%s&",ptr);
        web_get_info(IP_INFO,res+strlen(res));
    }else if(!strcmp(ptr,"cmd=net_config")){
        sprintf(res,"%s&",ptr);
        web_get_info(NET_CONFIG_INFO,res+strlen(res));
    }else if(!strcmp(ptr,"cmd=net_config_device")){
        sprintf(res,"%s&",ptr);
        web_get_info(NET_CONFIG_DEVICE,res+strlen(res));
    }else if(!strcmp(ptr,"cmd=sub_device_info")){
        sprintf(res,"%s&",ptr);
        web_get_info(SUB_DEVICE,res+ strlen(res));
    }else if(!strcmp(ptr,"cmd=adc_config_info")){
        sprintf(res,"%s&",ptr);
        web_get_info(ADC_CONFIG_INFO,res+ strlen(res));
    }

    if (pool != NULL) {
        memset(pool, 0, strlen(pool));//发送数据时在进行清空
    }
}

void deal_cli_exec(char *pool, char *res) {
    char *tmp;
    char argv[1024][256];
    int argc = 0;
    int len;

    while ((tmp = strsep(&pool, " ")) != NULL) { // " " 命令接卸的分隔符
        printf("cli deal %s\n", tmp);
        strncpy(argv[argc], tmp, 256);
        argc++;
    }
    len = (int) strlen(res);
    find_script_exec(argc, (char **) argv, res + len); //往不同的地址下进行数据的复制;
}

void check_cli_parse_deal(char *pool, char *res) {
    if (pool == NULL || res == NULL) {
        printf("Can't suport for cli mem\n");
    }

    if (strstr(pool, "CLI_MSG=FILE_SCRIPT:")) { //命令行的头部解析;只执行一次这个命令
        deal_script(pool + strlen("CLI_MSG=FILE_SCRIPT:"), res);
    } else if (strstr(pool, "CLI_MSG=EXEC:")) {
        deal_cli_exec(pool + strlen("CLI_MSG=EXEC:"), res);
    }
}

void *deal_web(void *arg) {
    int udp_fd = socket(AF_INET, SOCK_DGRAM, 0);
    int enable_select = 1;
    int recv_size = 0;

    unsigned char buffer[4096];
    if (setsockopt(udp_fd, SOL_SOCKET, SO_REUSEADDR, &enable_select, sizeof(int)) == -1) {
        printf("sys error:%s\n", strerror(errno));
    }

    struct sockaddr_in recv_addr, local_addr;
    local_addr.sin_family = AF_INET;
    local_addr.sin_port = htons(2021);
    local_addr.sin_addr.s_addr = INADDR_ANY;

    socklen_t addrlen = sizeof(struct sockaddr);
    int res = bind(udp_fd, (struct sockaddr *) &local_addr, addrlen);
    if (res < 0) {
        printf("sys error:%s\n", strerror(errno));
    }

    unsigned char packet_buffer[4096] = {0};
    while (1) { //如果没有数据线程被阻塞,直到可以接收到数据
        recv_size = recvfrom(udp_fd, buffer, 4096, 0, (struct sockaddr *) &recv_addr, &addrlen); //如果没有数据就等待数据
        if (recv_size > 0) {
//            printf("web deal recv；%s\n", buffer);
            check_and_deal_and_parse((char *) buffer, (char *) packet_buffer);
//            printf("packet buffer：%s %ld\n", packet_buffer, strlen(packet_buffer));
//            printf("%#x\n", recv_addr.sin_addr.s_addr);
            if (sendto(udp_fd, packet_buffer, strlen(packet_buffer), 0, (struct sockaddr *) &recv_addr, addrlen) < 0) {
                printf("send web res error %s\n", strerror(errno));
                goto ERROR;
            }
            recv_size = 0;
            bzero((struct sockaddr *) &recv_addr, addrlen);
            memset(packet_buffer, 0, sizeof(packet_buffer));
        }
        ERROR:
        recv_size = 0;
        bzero((struct sockaddr *) &recv_addr, addrlen);
        memset(buffer, 0, 2048);
    }
    return NULL;
}

void web_thread_deal(void) {
    pthread_t web_pid;
    pthread_attr_t web_pid_attr;
    pthread_attr_init(&web_pid_attr);
    pthread_attr_setdetachstate(&web_pid_attr, PTHREAD_CREATE_DETACHED); //分离后系统回收线程资源

    printf("start web deal thread\n");
    if (pthread_create(&web_pid, &web_pid_attr, deal_web, NULL) < 0) {
        printf("creare thread for web deal error");
    }
}

void *deal_cli(void *arg) {
    int udp_fd = socket(AF_INET, SOCK_DGRAM, 0);
    int enable_select = 1;
    int recv_size = 0;

    unsigned char buffer[4096];
    if (setsockopt(udp_fd, SOL_SOCKET, SO_REUSEADDR, &enable_select, sizeof(int)) == -1) {
        printf("sys error:%s\n", strerror(errno));
    }

    struct sockaddr_in recv_addr, local_addr;
    local_addr.sin_family = AF_INET;
    local_addr.sin_port = htons(2022); //2022 端口为与命令行同信并使用的端口;
    local_addr.sin_addr.s_addr = INADDR_ANY;

    socklen_t addrlen = sizeof(struct sockaddr);
    int res = bind(udp_fd, (struct sockaddr *) &local_addr, addrlen);
    if (res < 0) {
        printf("sys error:%s\n", strerror(errno));
    }

    unsigned char packet_buffer[4096] = {0};
    while (1) { //如果没有数据线程被阻塞,直到可以接收到数据 //不适用延时进行接受
        recv_size = recvfrom(udp_fd, buffer, 4096, 0, (struct sockaddr *) &recv_addr, &addrlen); //如果没有数据就等待数据
        if (recv_size > 0) {
//            printf("cli deal recv；%s\n", buffer);
            check_cli_parse_deal((char *) buffer, (char *) packet_buffer);
//            printf("packet buffer：%s %ld\n", packet_buffer, strlen(packet_buffer));
            if (sendto(udp_fd, packet_buffer, strlen(packet_buffer), 0, (struct sockaddr *) &recv_addr, addrlen) < 0) {
                printf("send cli res error %s\n", strerror(errno));
                goto ERROR;
            }
            recv_size = 0;
            bzero((struct sockaddr *) &recv_addr, addrlen);
            memset(packet_buffer, 0, sizeof(packet_buffer));
        }
        ERROR:
        recv_size = 0;
        bzero((struct sockaddr *) &recv_addr, addrlen);
        memset(buffer, 0, 2048);
    }
    return NULL;
}

void cli_thread_deal(void) {
    pthread_t cli_pid;
    pthread_attr_t cli_attr;
    pthread_attr_init(&cli_attr);
    pthread_attr_setdetachstate(&cli_attr, PTHREAD_CREATE_DETACHED);
    printf("Cli deal thread start\n");

    if (pthread_create(&cli_pid, &cli_attr, deal_cli, NULL) < 0) {
        printf("create thread for cli deal error");
    }
}

int main() {
    clock_t start, stop;
    int i = 0;
    double s = 0;
    start = clock();
    int all_len, config_len;
    int ret = init_web_data(&all_len, &config_len); //首先进行参数初始化,没有初始化文件，不在启动Web处理程序
    if (ret == 0) {
        init_web_database(all_len);
    //    init_main();
//        COM_LIST_HEAD_t *cur;
//        map_list *search;
//        list_each(cur, &web_data_list) {
//            search = list_node_get(cur, map_list, node);
//            if (search != NULL) {
//                printf("name: %d\n", search->select);
//            }
//        }
        web_thread_deal(); //后台服务处理程序

    }
    cli_thread_deal();
//    stop = clock();
//    printf("start:%ld\n", start);
//    printf("end:%ld\n", stop);
//    printf("CLOCK:%ld\n", CLOCKS_PER_SEC);
//    s = (double) (stop - start) / (double) CLOCKS_PER_SEC;
//    printf("cost time %.12lf\n", s);
    while (1) {
        sleep(10);
    }

    return 0;
}